package dhy.com.tomcat.four.request;



import dhy.com.tomcat.four.core.stream.SocketInputStream;
import dhy.com.tomcat.four.param.ParameterMap;
import dhy.com.tomcat.four.request.utils.RequestUtil;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @author 大忽悠
 * @create 2022/3/9 18:12
 */
public class HttpRequest implements ServletRequest {
    private String queryString;
    private String protocol;
    private String sessionId;
    private String method;
    private String requestUri;
    private boolean sessionURL;
    private boolean cookieURL;
    private Map<String, String> headers = new HashMap<>();
    /**
     * 最大cookie数量
     */
    private final int DEFAULT_MAX_COOKIE_SIZE = 100;
    private List<Cookie> cookies = new ArrayList<>();
    private int contentLength;
    private Object contentType;
    private boolean parsed;
    private ParameterMap parameters;
     private SocketInputStream inputStream;

    public HttpRequest(SocketInputStream input) {
    inputStream=input;
    }
    
    public void addCookie(Cookie cookie) throws ServletException {
        if (cookies.size() + 1 > DEFAULT_MAX_COOKIE_SIZE) {
            throw new ServletException("over max cookies size!");
        }
        cookies.add(cookie);
    }

    public void setContentLength(int n) {
        this.contentLength = n;
    }

    public void setContentType(String value) {
        this.contentType = value;
    }

    protected void parseParameters() {
        if (parsed)
        {
            //如果已经解析过了，直接返回
            return;
        }
        ParameterMap results = parameters;
        if (results == null) {
            results = new ParameterMap();
        }
        //打开 parameterMap的锁以便写值。
        results.setLocked(false);
        //获得字符编码
        String encoding = getCharacterEncoding();
        //检查字符编码，并在字符编码为 null的时候赋予默认字符编码。
        if (encoding == null){
            encoding = "UTF-8";
        }
        //getQueryString方法在上一节解析了请求头时，如果URL如果有查询参数有设置。
        //尝试解析查询字符串。解析参数是使用org.apache.Catalina.util.RequestUtil的 parseParameters方法来处理的。
        //如果queryString为空(URL中没有参数)，下面parseParameters方法的的解析直接返回
        String queryString = getQueryString();
        //解析请求参数---Get方式拼接在URL后面的
        RequestUtil.parseParameters(results, queryString, encoding);

        //获取内容类型
        String contentType = getContentType();
        if (contentType == null){
            contentType = "";
        }
        int semicolon = contentType.indexOf(';');
        if (semicolon >= 0) {
            contentType = contentType.substring(0, semicolon).trim();
        } else {
            contentType = contentType.trim();
        }

        //请求参数在请求体中
        //请求方式是POST(内容长度大于零)且内容类型是 application/x-www-form-urlencoded
        //同样用parseParameters解析POST中的内容
        if ("POST".equals(getMethod()) && (getContentLength() > 0)
                && "application/x-www-form-urlencoded".equals(contentType)) {
            try {
                //请求行----请求头----请求体
                int max = getContentLength();
                int len = 0;
                byte buf[] = new byte[max];
                ServletInputStream is = getInputStream();
                while (len < max) {
                    int next = is.read(buf, len, max - len);
                    if (next < 0) {
                        break;
                    }
                    len += next;
                }
                is.close();
                if (len < max) {
                    throw new RuntimeException("Content length mismatch");
                }
                RequestUtil.parseParameters(results, String.valueOf(buf), encoding);
            } catch (UnsupportedEncodingException ue) {
                ;
            } catch (IOException e) {
                throw new RuntimeException("Content read fail");
            }
        }

        //锁定 ParameterMap表示不可修改参数
        //设置 parsed为 true表示已经解析过了，
        results.setLocked(true);
        parsed = true;
        parameters = results;
    }

    private String getMethod() {
      return method;
    }

    private String getQueryString() {
      return queryString;
    }


    @Override
    public Object getAttribute(String s) {
        return null;
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        return null;
    }

    @Override
    public String getCharacterEncoding() {
        return null;
    }

    @Override
    public void setCharacterEncoding(String s) throws UnsupportedEncodingException {

    }

    @Override
    public int getContentLength() {
        return contentLength;
    }

    @Override
    public long getContentLengthLong() {
        return 0;
    }

    @Override
    public String getContentType() {
        return null;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return null;
    }

    @Override
    public String getParameter(String s) {
        //请求还没解析
        if(!parsed)
        {
            parseParameters();
        }
        return (String) parameters.get(s);
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return null;
    }

    @Override
    public String[] getParameterValues(String s) {
        return new String[0];
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        return null;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getScheme() {
        return null;
    }

    @Override
    public String getServerName() {
        return null;
    }

    @Override
    public int getServerPort() {
        return 0;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return null;
    }

    @Override
    public String getRemoteAddr() {
        return null;
    }

    @Override
    public String getRemoteHost() {
        return null;
    }

    @Override
    public void setAttribute(String s, Object o) {

    }

    @Override
    public void removeAttribute(String s) {

    }

    @Override
    public Locale getLocale() {
        return null;
    }

    @Override
    public Enumeration<Locale> getLocales() {
        return null;
    }

    @Override
    public boolean isSecure() {
        return false;
    }

    @Override
    public RequestDispatcher getRequestDispatcher(String s) {
        return null;
    }

    /**
     * @param s
     * @deprecated
     */
    @Override
    public String getRealPath(String s) {
        return null;
    }

    @Override
    public int getRemotePort() {
        return 0;
    }

    @Override
    public String getLocalName() {
        return null;
    }

    @Override
    public String getLocalAddr() {
        return null;
    }

    @Override
    public int getLocalPort() {
        return 0;
    }

    @Override
    public ServletContext getServletContext() {
        return null;
    }

    @Override
    public AsyncContext startAsync() throws IllegalStateException {
        return null;
    }

    @Override
    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
        return null;
    }

    @Override
    public boolean isAsyncStarted() {
        return false;
    }

    @Override
    public boolean isAsyncSupported() {
        return false;
    }

    @Override
    public AsyncContext getAsyncContext() {
        return null;
    }

    @Override
    public DispatcherType getDispatcherType() {
        return null;
    }

    public void addHeader(String key, String value) {
        headers.put(key,value);
    }

    public void setRequestedSessionId(String value) {
       sessionId=value;
    }

    public void setRequestedSessionCookie(boolean b) {
      cookieURL=b;
    }

    public void setRequestedSessionURL(boolean b) {
        sessionURL=b;
    }

    public void setQueryString(String queryString) {
        this.queryString=queryString;
    }

    public void setMethod(String method) {
      this.method=method;
    }

    public void setProtocol(String protocol) {
        this.protocol=protocol;
    }

    public void setRequestURI(String normalizedUri) {
        this.requestUri=normalizedUri;
    }

    public String getUri() {
        return requestUri;
    }
}
